/**
 * Author: Jackin (qin.zhang@uni.lu)
 * Date: August, 2013
 * (c) 2013 University of Luxembourg - Interdisciplinary Centre for Security Reliability and Trust (SnT)
 * All rights reserved
 * GPLv3 to be found at: http://www.gnu.org/licenses/quick-guide-gplv3.html
 */

package lu.uni.geko.ext.ram;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import lu.uni.geko.common.GeKoConstants;
import lu.uni.geko.resources.MainResourceLoader;
import lu.uni.geko.util.bridges.EMFBridge;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.util.EcoreUtil;

/**
 * This is a utility class that offers static methods for additional operations on RAM aspects which are necessary for
 * model weaving process, e.g. instantiating the dependent aspects before weaving, etc.
 * 
 * @author Jackin
 */
public final class RamUtil
{

	public static final URI copyBaseToWovenURI(URI baseURI)
	{
		EObject baseRootElement = MainResourceLoader.getUniqueContentRoot(baseURI, "base model");
		EObject wovenRootElement = EcoreUtil.copy(baseRootElement);
		URI wovenURI = EMFBridge.newURIWithStringAppendedToFilename(baseURI, GeKoConstants.getWovenMFilenameAppendage());
		MainResourceLoader.saveEObjectAsOnlyContent(wovenRootElement, wovenURI);
		return wovenURI;
	}

	public static final void changeVisibility(ram.Aspect aspect)
	{
		for (ram.Classifier iClass : aspect.getStructuralView().getClasses())
		{
			for (ram.Operation iOp : ((ram.Class) iClass).getOperations())
				if (iOp.getVisibility().getValue() == ram.Visibility.PUBLIC_VALUE)
					iOp.setVisibility(ram.Visibility.PACKAGE);
		}
	}

	/**
	 * Make an advice copy of the base element by appending advice package suffix to the base package name
	 * 
	 * @param eObject
	 *          The base element
	 * @return An Advice copy of the base element
	 */
	public static final EObject copyAdvice(final EObject eObject)
	{
		RamCopier copier = new RamCopier(GeKoConstants.getAvMMPkgNsURIAppendage());
		return copier.copy(eObject);
	}

	public static final void buildDefaultMappings(ram.Aspect base, ram.Aspect dependent, ram.Instantiation instantiation)
	{
		// Todo
	}

	public static final void instantiate(ram.Instantiation instantiation)
	{
		/*
		 * Note that the to-element is located in the base model, and the from-element is in the dependent model.
		 * 
		 * Be careful that when instantiate the dependent aspect, not only the name but also other attributes should be
		 * overridden by the corresponding ones in the base aspect.
		 */
		for (ram.ClassifierMapping classifierMapping : instantiation.getMappings())
		{
			// class mapping
			ram.Class baseClass = (ram.Class) classifierMapping.getToElement();
			ram.Class avClass = (ram.Class) classifierMapping.getFromElement();

			avClass.setName(baseClass.getName());

			if (baseClass.isAbstract())
				avClass.setAbstract(true);
			else
				avClass.setAbstract(false);

			if (baseClass.isPartial())
				avClass.setPartial(true);
			else
				avClass.setPartial(false);

			// attribute mapping
			if (classifierMapping.getAttributeMappings() != null)
				for (ram.AttributeMapping attributeMapping : classifierMapping.getAttributeMappings())
				{
					ram.Attribute baseAttribute = attributeMapping.getToElement();
					ram.Attribute avAttribute = attributeMapping.getFromElement();

					avAttribute.setName(baseAttribute.getName());

					if (baseAttribute.isStatic())
						avAttribute.setStatic(true);
					else
						avAttribute.setStatic(false);

					avAttribute.setType(baseAttribute.getType());
				}

			// operation mapping
			if (classifierMapping.getOperationMappings() != null)
			{
				for (ram.OperationMapping operationMapping : classifierMapping.getOperationMappings())
				{
					ram.Operation baseOperation = operationMapping.getToElement();
					ram.Operation avOperation = operationMapping.getFromElement();

					avOperation.setName(baseOperation.getName());
					avOperation.setReturnType(baseOperation.getReturnType());
					avOperation.setVisibility(baseOperation.getVisibility());

					if (baseOperation.isAbstract())
						avOperation.setAbstract(true);
					else
						avOperation.setAbstract(false);

					if (baseOperation.isPartial())
						avOperation.setPartial(true);
					else
						avOperation.setPartial(false);

					if (baseOperation.isStatic())
						avOperation.setStatic(true);
					else
						avOperation.setStatic(false);

					// parameter mapping
					if (operationMapping.getParameterMappings() != null)
						for (ram.ParameterMapping parameterMapping : operationMapping.getParameterMappings())
						{
							ram.Parameter baseParameter = parameterMapping.getToElement();
							ram.Parameter avParameter = parameterMapping.getFromElement();

							avParameter.setName(baseParameter.getName());
							avParameter.setType(baseParameter.getType());
						}
				}
			}
		} // end of for(ClassifierMapping)
	}
	

}
